home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-06-16 | 14.4 KB | 753 lines | [TEXT/MPS ] |
- /*
- Two-Dimensional Clipping: A Vector Based Approach
- by Hans Spoelder and Fons Ullings
- from "Graphics Gems", Academic Press, 1990
- */
-
-
- line.h
-
- /*
- * file line.h
- * contains major definitions for the clipping routines
- *
- */
- #define NFAC 10 /* discrete measure */
-
- #define SCALE (1 << NFAC) /* 1024 points/cm */
- #define TO_INT(X) ((int)((X)*SCALE))
- #define TO_FLT(X) (((float)(X))/SCALE)
-
- #define COINCIDE 1 /* what do the lines do */
- #define PARALLEL 2
- #define CROSS 3
- #define NO_CROSS 4
-
- #define STD 0 /* crossing types */
- #define DELAY 1
-
- #define CLIP_NORMAL 1
-
- typedef struct { /* holds a point */
- long _x; /* holds x coordinate */
- long _y; /* holds y coordinate */
- } POINT;
-
- typedef struct { /* holds a cross point */
- POINT _p; /* holds the solution */
- short _type; /* more information */
- } CLIST;
-
- struct segment { /* holds a segment */
- POINT _from; /* start coordinates */
- POINT _to; /* stop coordinates */
- struct segment *_next;
- struct segment *_prev;
- };
-
-
- #define SEGMENT struct segment
-
- struct contour { /* holds a contour */
- short _no; /* contour counter */
- short _status; /* holds information */
- short _cnt; /* number of elements */
- SEGMENT *_s; /* the segments */
- struct contour *_next; /* linked list */
- long _minx; /* coordinates of box */
- long _miny;
- long _maxx;
- long _maxy;
- };
-
- #define CONTOUR struct contour
-
- #define ACTIVE 01 /* polygon attributes */
- #define NORMAL 02
-
- #define SET_ON(p) ((p)->_status |= ACTIVE)
- #define SET_NORMAL(p) ((p)->_status |= NORMAL)
-
- #define SET_OFF(p) ((p)->_status &= ~ACTIVE)
- #define SET_INVERSE(p) ((p)->_status &= ~NORMAL)
-
- #define IS_ON(p) ((p)->_status & ACTIVE)
- #define IS_NORMAL(p) ((p)->_status & NORMAL)
-
- extern CONTOUR *CL;
-
- CONTOUR *get_contour_ptr();
-
- extern short C_COUNT;
-
- box.h
-
- /*
- * file box.h
- * a short include file is better then no include file
- */
- typedef struct { /* guess what this is */
- long _lowx;
- long _lowy;
- long _highx;
- long _highy;
- } BOX;
-
-
- bio1.c
-
- /*
- * file bio.c
- * contains the basic operations
- *
- */
- #include <stdio.h>
- #include "line.h"
-
- /*
- * def_contour
- *
- * Purpose:
- * add a contour to the list
- * NOTE: coordinates must already be converted into longs!
- *
- * x x coordinates of the end points of segments
- * y y coordinates of the end points of segments
- * n number of coordinate pairs
- * no contour number (id), does no have to be unique!
- * type type of clip operation desired CLIP_NORMAL means
- * clip everything inside the contour
- */
- def_contour(x, y, n, no, type)
- long x[], y[];
- int n, no, type;
- {
- short i;
- long dx1, dx2, dy1, dy2;
- long minx, miny, maxx, maxy;
- CONTOUR *cp;
- SEGMENT *sp, *spp;
-
- if((cp = CL) == (CONTOUR *)NULL) {
- cp = CL = NEWTYPE(CONTOUR);
- }
- else {
- while(cp->_next != (CONTOUR *)NULL)
- cp = cp->_next;
- i = cp->_no;
- cp = cp->_next = NEWTYPE(CONTOUR);
- }
-
- cp->_next = (CONTOUR *)NULL;
- cp->_no = no;
- SET_ON(cp);
- if(type == CLIP_NORMAL)
- SET_INVERSE(cp);
- else
- SET_NORMAL(cp);
- minx = miny = 1000000;
- maxx = maxy = -1;
- for(i=0; i<n; i++) {
- if(i == 0) {
- cp->_s = sp = NEWTYPE(SEGMENT);
- sp->_from._x = x[0];
- sp->_from._y = y[0];
- sp->_to._x = x[1];
- sp->_to._y = y[1];
- }
- else {
- /*
- * if necessary stretch the contour
- * and skip the point
- */
- dx1 = sp->_to._x - sp->_from._x;
- dy1 = sp->_to._y - sp->_from._y;
- dx2 = x[(i == n-1) ? 0 : i+1] - sp->_to._x;
- dy2 = y[(i == n-1) ? 0 : i+1] - sp->_to._y;
- if(dy2*dx1 == dy1*dx2) {
- sp->_to._x = x[(i == n-1) ? 0 : i+1];
- sp->_to._y = y[(i == n-1) ? 0 : i+1];
- }
- else {
- spp = sp;
- sp = sp->_next = NEWTYPE(SEGMENT);
- sp->_prev = spp;
- sp->_from._x = x[i];
- sp->_from._y = y[i];
- sp->_to._x = x[(i == n-1) ? 0 : i+1];
- sp->_to._y = y[(i == n-1) ? 0 : i+1];
- }
- }
-
- /*
- * calculate the enclosing box
- */
- if(x[i] < minx)
- minx = x[i];
- if(x[i] > maxx)
- maxx = x[i];
- if(y[i] < miny)
- miny = y[i];
- if(y[i] > maxy)
- maxy = y[i];
-
- }
- cp->_minx = minx;
- cp->_maxx = maxx;
- cp->_miny = miny;
- cp->_maxy = maxy;
- sp->_next = cp->_s;
- cp->_s->_prev = sp;
- cp->_next = (CONTOUR *)NULL;
- }
-
- /*
- * get_contour_ptr
- *
- * PURPOSE
- * get the pointer to a contour given its id
- * with multiple id's first fit algorithm is
- * used. Returns NULL in case of error.
- *
- * no id of contour
- */
- CONTOUR *get_contour_ptr(no)
- int no;
- {
- CONTOUR *cp;
-
- if((cp = CL) == (CONTOUR *)NULL)
- return((CONTOUR *)NULL);
- else {
- while(cp != (CONTOUR *)NULL) {
- if(cp->_no == no)
- return(cp);
- else
- cp = cp->_next;
- }
- return((CONTOUR *)NULL);
- }
- }
-
-
- /*
- * del_contour
- *
- * PURPOSE
- * delete contour(s) from the list with id
- * no
- */
- del_contour(no)
- int no;
- {
- CONTOUR *cp, *cpp;
- CONTOUR *qp = (CONTOUR *)NULL;
- SEGMENT *sp, *spp;
-
- if((cp = CL) == (CONTOUR *)NULL)
- return;
- while(cp != (CONTOUR *)NULL) {
- if(cp->_no == no) {
- sp = cp->_s;
- do {
- spp = sp->_next;
- free(sp);
- sp = spp;
- } while(sp != cp->_s);
- cpp = cp->_next;
- free(cp);
- if(qp)
- qp->_next = cpp;
- else
- CL = cpp;
- cp = cpp;
- }
- else {
- qp = cp;
- cp = cp->_next;
- }
- }
- }
-
-
- cross1.c
-
- /*
- * file cross.c:
- * calculate the intersections
- */
- #include <math.h>
- #include "line.h"
- #include "box.h"
- /*
- * cross_calc:
- *
- * PURPOSE
- * calculate the intersections between the polygon
- * stored in poly and the linesegment stored in l
- * and put the intersections into psol.
- *
- * poly pointer to the structure containing the polygon
- * l pointer to the structure containing the linesegment
- * psol pointer to the pointer where intersections are stored
- * nsol current number of intersections stored
- * nsmax maximum storage in psol for intersections
- * if nsol exceeds nsmax additional storage is allocated
- *
- */
- cross_calc(poly, l, psol, nsol, nsmax)
- CONTOUR *poly;
- SEGMENT *l;
- CLIST **psol;
- short *nsol, nsmax;
- {
- SEGMENT *p;
- CLIST *sol;
- double s;
- long x, y, a, b, c;
- int psort(), type;
-
- sol = *psol;
- p = poly->_s;
- do {
- /*
- * calculate the a, b and c coefficients and determine the
- * type of intersection
- */
-
- a = (p->_to._y - p->_from._y)*(l->_to._x - l->_from._x) -
- (p->_to._x - p->_from._x)*(l->_to._y - l->_from._y);
- b = (p->_from._x - l->_from._x)*(l->_to._y - l->_from._y) -
- (p->_from._y - l->_from._y)*(l->_to._x - l->_from._x);
- c = (p->_from._x - l->_from._x)*(p->_to._y - p->_from._y) -
- (p->_from._y - l->_from._y)*(p->_to._x - p->_from._x);
- if(a == 0)
- type = (b == 0) ? COINCIDE : PARALLEL;
- else {
- if(a > 0) {
- if((b >= 0 && b <= a) &&
- (c >= 0 && c <= a))
- type = CROSS;
- else
- type = NO_CROSS;
- }
- else {
- if((b <= 0 && b >= a) &&
- (c <= 0 && c >= a))
- type = CROSS;
- else
- type = NO_CROSS;
- }
- }
- /*
- * process the interscetion found
- */
- switch(type) {
- case NO_CROSS: case PARALLEL:
- break;
-
- case CROSS:
- if(b == a || c == a || c == 0)
- break;
- if(b == 0 &&
- p_where(&(p->_prev->_from), &(p->_to), l) >= 0)
- break;
- s = (double)b/(double)a;
- if(l->_from._x == l->_to._x)
- x = l->_from._x;
- else
- x = p->_from._x +
- (int)((p->_to._x - p->_from._x)*s);
- if(l->_from._y == l->_to._y)
- y = l->_from._y;
- else
- y = p->_from._y +
- (int)((p->_to._y - p->_from._y)*s);
-
- if(*nsol == nsmax) {
- nsmax *= 2;
- *psol = sol = (CLIST *) realloc(sol, nsmax*sizeof(CLIST));
- }
- sol[*nsol]._p._x = x;
- sol[*nsol]._p._y = y;
- sol[*nsol]._type = STD;
- *nsol += 1;
- break;
-
- case COINCIDE:
- if(p_where(&(p->_prev->_from),
- &(p->_next->_to), l) > 0)
- break;
- if(l->_from._x != l->_to._x) {
- if((max(l->_from._x, l->_to._x) <
- min(p->_from._x, p->_to._x) ) ||
- (min(l->_from._x, l->_to._x) >
- max(p->_from._x, p->_to._x)) )
- break;
- if(min(l->_from._x, l->_to._x) <
- min(p->_from._x, p->_to._x) ) {
- if(*nsol == nsmax) {
- nsmax *= 2;
- *psol = sol = (CLIST *) realloc(sol, nsmax*sizeof(CLIST));
- }
- sol[*nsol]._p._x = p->_from._x;
- sol[*nsol]._p._y = p->_from._y;
- sol[*nsol]._type = DELAY;
- *nsol += 1;
- }
- if(max(l->_from._x, l->_to._x) >
- max(p->_from._x, p->_to._x) ) {
- if(*nsol == nsmax) {
- nsmax *= 2;
- *psol = sol = (CLIST *) realloc(sol, nsmax*sizeof(CLIST));
- }
- sol[*nsol]._p._x = p->_to._x;
- sol[*nsol]._p._y = p->_to._y;
- sol[*nsol]._type = DELAY;
- *nsol += 1;
- }
- }
- else {
-
- if((max(l->_from._y, l->_to._y) <
- min(p->_from._y, p->_to._y) ) ||
- (min(l->_from._y, l->_to._y) >
- max(p->_from._y, p->_to._y)) )
- break;
- if(min(l->_from._y, l->_to._y) <
- min(p->_from._y, p->_to._y) ) {
- if(*nsol == nsmax) {
- nsmax *= 2;
- *psol = sol = (CLIST *) realloc(sol, nsmax*sizeof(CLIST));
- }
- sol[*nsol]._p._x = p->_from._x;
- sol[*nsol]._p._y = p->_from._y;
- sol[*nsol]._type = DELAY;
- *nsol += 1;
- }
- if(max(l->_from._y, l->_to._y) >
- max(p->_from._y, p->_to._y) ) {
- if(*nsol == nsmax) {
- nsmax *= 2;
- *psol = sol = (CLIST *) realloc(sol, nsmax*sizeof(CLIST));
- }
- sol[*nsol]._p._x = p->_to._x;
- sol[*nsol]._p._y = p->_to._y;
- sol[*nsol]._type = DELAY;
- *nsol += 1;
- }
- }
- break;
- }
- p = p->_next;
- } while(p != poly->_s);
- qsort(sol, *nsol, sizeof(CLIST), psort);
- }
-
-
- /*
- * p_where
- *
- * PURPOSE
- * determine position of point p1 and p2 relative to
- * linesegment l.
- * Return value
- * < 0 p1 and p2 lie at different sides of l
- * = 0 one of both points lie on l
- * > 0 p1 and p2 lie at same side of l
- *
- * p1 pointer to coordinates of point
- * p2 pointer to coordinates of point
- * l pointer to linesegment
- *
- */
- p_where(p1, p2, l)
- POINT *p1, *p2;
- SEGMENT *l;
- {
- long dx, dy, dx1, dx2, dy1, dy2, p_1, p_2;
-
- dx = l->_to._x - l->_from._x;
- dy = l->_to._y - l->_from._y;
- dx1 = p1->_x - l->_from._x;
- dy1 = p1->_y - l->_from._y;
- dx2 = p2->_x - l->_to._x;
- dy2 = p2->_y - l->_to._y;
- p_1 = (dx*dy1 - dy*dx1);
- p_2 = (dx*dy2 - dy*dx2);
- if(p_1 == 0 || p_2 == 0)
- return(0);
- else {
- if((p_1 > 0 && p_2 < 0) || (p_1 < 0 && p_2 > 0))
- return(-1);
- else
- return(1);
- }
- }
-
-
- /*
- * p_inside
- *
- * PURPOSE
- * determine if the point stored in pt lies inside
- * the polygon stored in p
- * Return value:
- * FALSE pt lies outside p
- * TRUE pt lies inside p
- *
- * p pointer to the polygon
- * pt pointer to the point
- */
- boolean p_inside(p, pt)
- CONTOUR *p;
- POINT *pt;
- {
- SEGMENT l, *sp;
- CLIST *sol;
- short nsol = 0, nsmax = 2, reduce = 0, i;
- boolean on_contour(), odd;
-
- l._from._x = p->_minx-2;
- l._from._y = pt->_y;
- l._to._x = pt->_x;
- l._to._y = pt->_y;
- sol = (CLIST *) calloc(2, sizeof(CLIST));
- cross_calc(p, &l, &sol, &nsol, nsmax);
- for(i=0; i<nsol-1; i++)
- if(sol[i]._type == DELAY && sol[i+1]._type == DELAY)
- reduce++;
- free(sol);
- odd = (nsol - reduce) & 0x01;
- return(odd ? !on_contour(p, pt) : FALSE);
- }
-
- /*
- * function used for sorting
- */
- psort(p1, p2)
- CLIST *p1, *p2;
- {
- if(p1->_p._x != p2->_p._x)
- return(p1->_p._x - p2->_p._x);
- else
- return(p1->_p._y - p2->_p._y);
- }
-
-
- /*
- * on_contour
- *
- * PURPOSE
- * determine if the point pt lies on the
- * contour p.
- * Return value
- * TRUE point lies on contour
- * FALSE point lies not on contour
- *
- * p pointer to the polygon structure
- * pt pointer to the point
- */
- boolean on_contour(p, pt)
- CONTOUR *p;
- POINT *pt;
- {
- SEGMENT *sp;
- long dx1, dy1, dx2, dy2;
-
- sp = p->_s;
- do {
- if((pt->_x >= min(sp->_from._x, sp->_to._x)) &&
- (pt->_x <= max(sp->_from._x, sp->_to._x)) ) {
- dx1 = pt->_x - sp->_from._x;
- dx2 = sp->_to._x - pt->_x;
- dy1 = pt->_y - sp->_from._y;
- dy2 = sp->_to._y - pt->_y;
- if(dy1*dx2 == dy2*dx1)
- return(TRUE);
- }
- sp = sp->_next;
- } while(sp != p->_s);
- return(FALSE);
- }
-
- clip1.c
-
- /*
- * file clip.c
- * contains the actual clipping routines
- */
- #include <stdio.h>
- #include "line.h"
-
-
- /*
- * vis_vector
- *
- * PURPOSE
- * actual user interface. Draws a clipped line
- * NOTE: coordinates are given in converted LONGS!
- *
- * xf, yf from coordinates of vector to be drawn
- * xt, yt to coordinates of vector to be drawn
- */
- vis_vector(xf, yf, xt, yt)
- long xf, yf, xt, yt;
- {
- SEGMENT l;
-
- if(xf == xt && yf == yt)
- return;
- l._from._x = xf;
- l._from._y = yf;
- l._to._x = xt;
- l._to._y = yt;
- /*
- * start at top of list
- */
- clip(CL, &l);
- }
-
- /*
- * clip
- *
- * PURPOSE
- *
- * p pointer to polygon
- * l pointer to line segment
- */
- clip(p, l)
- CONTOUR *p;
- SEGMENT *l;
- {
- SEGMENT *sp, ss;
- CLIST *sol;
- POINT pt;
- boolean up, delay, inside, p_inside(), disjunct();
- int i;
- short nsol, nsmax = 2;
-
-
- /*
- * list exhausted do what you like
- * we want to plot
- */
- if(p == (CONTOUR *)NULL) {
- move((l->_from._x), (l->_from._y));
- cont((l->_to._x), (l->_to._y));
- return;
- }
- /*
- * polygon is switched off
- * take next one
- */
- if(!IS_ON(p)) {
- clip(p->_next, l);
- return;
- }
- /*
- * comparison on basis of the
- * enclosing rectangle
- */
- if(disjunct(p, l)) {
- if(!IS_NORMAL(p)) {
- clip(p->_next, l);
- }
- return;
- }
- /*
- * calculate possible intersections
- */
- sol = (CLIST *) calloc(2, sizeof(CLIST));
- sol[0]._p._x = l->_from._x;
- sol[0]._p._y = l->_from._y;
- sol[0]._type = STD;
- sol[1]._p._x = l->_to._x;
- sol[1]._p._y = l->_to._y;
- sol[1]._type = STD;
- nsol = 2;
- cross_calc(p, l, &sol, &nsol, nsmax);
- pt._x = sol[0]._p._x;
- pt._y = sol[0]._p._y;
-
- /*
- * determine status of first point
- */
- inside = p_inside(p, &pt);
- if((!inside && IS_NORMAL(p)) || (inside && !IS_NORMAL(p)))
- up = TRUE;
- else
- up = FALSE;
- delay = FALSE;
- /*
- * process list of intersections
- */
- for(i=1; i<nsol; i++) {
- if(!up) {
- ss._from._x = sol[i-1]._p._x;
- ss._from._y = sol[i-1]._p._y;
- ss._to._x = sol[i]._p._x;
- ss._to._y = sol[i]._p._y;
- clip(p->_next, &ss);
- }
- if(!delay) {
- if(sol[i]._type != DELAY)
- up = (up) ? FALSE : TRUE
- else
- delay = TRUE;
- }
- else {
- up = (up) ? FALSE : TRUE;
- delay = FALSE;
- }
- }
- free(sol);
- }
-
- /*
- * disjunct
- *
- * PURPOSE
- * determine if the box enclosing the polygon
- * stored in p and the box enclosing the line
- * segment stored in l are disjunct.
- * Return TRUE if disjunct else FALSE
- *
- * p points to the polygon structure
- * l points to the linesegment structure
- *
- */
- boolean disjunct(p, l)
- CONTOUR *p;
- SEGMENT *l;
-
- {
- if((max(l->_from._x, l->_to._x) < p->_minx) ||
- (min(l->_from._x, l->_to._x) > p->_maxx) ||
- (max(l->_from._y, l->_to._y) < p->_miny) ||
- (min(l->_from._y, l->_to._y) > p->_maxy) )
- return(TRUE);
- else
- return(FALSE);
- }
-
- #define DEBUG
- #ifdef DEBUG
- move(x, y)
- long x, y;
- {
- printf("(%d,%d) ->", x, y);
- }
-
- cont(x, y)
- long x, y;
- {
- printf("(%d,%d)\n", x, y);
- }
-
- #endif
-
-
-
-
-